/****************************************************************
 * <strong>MFDataTransfer数据转换类</strong>
 *
 * <p>
 * 数据转换类
 * </p>
 *
 * @author AndyZhang 2011
 * @version 0.1
 * ToDo:
 ***************************************************************/

package com.thinkwide.data.ormapping;

import com.thinkwide.data.config.GlobalConfig;
import com.thinkwide.data.util.CaseUtils;
import com.thinkwide.data.core.MFString;
import com.thinkwide.data.ormapping.annotation.MFField;
import com.thinkwide.data.ormapping.annotation.MFTable;
import com.thinkwide.data.ormapping.annotation.MFTableView;
import com.thinkwide.data.ormapping.datatable.MFDataColumn;
import com.thinkwide.data.ormapping.datatable.MFDataColumnException;
import com.thinkwide.data.ormapping.datatable.MFDataRow;
import com.thinkwide.data.ormapping.datatable.MFDataTable;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;


public class MFDataTransfer {
    public static MFDataTable getDataTable(MFDataAdapter adapter, ResultSet rs) throws SQLException, MFDataColumnException {
        MFDataTable dt = new MFDataTable();

        ResultSetMetaData metaData = rs.getMetaData();
        int count = metaData.getColumnCount();

        for (int i = 1; i <= count; i++) {
            String colName = metaData.getColumnName(i);
            String colType = metaData.getColumnTypeName(i);

            MFDataColumn col = new MFDataColumn(colName, colName, colType);
            col.setLength(metaData.getColumnDisplaySize(i));
            col.setPrecision(metaData.getPrecision(i));
            col.setScale(metaData.getScale(i));
            dt.getColumns().addColumn(col);
        }

        MFDbTypeCheck check = new MFDbTypeCheck(adapter);
        check.setTableDbType(dt);

        while (rs.next()) {

            MFDataRow row = dt.newRow();
            for (int i = 0; i < count; i++) {
                Object sqlTypeValue = rs.getObject(i + 1);
                if (sqlTypeValue != null && (sqlTypeValue.getClass().toString().toUpperCase().indexOf("CLOB") != -1)) {
                    sqlTypeValue = MFDbTypeTransfer.toJavaClob(sqlTypeValue);
                }

                row.setValue(i, sqlTypeValue);

            }

        }

        return dt;
    }

    public static String getPropValue(Object obj, String feildName) throws Throwable {
        return MFDbTypeTransfer.toJavaString(MFReflect.getProperty(obj, MFReflect.getRealPropertyName(obj, feildName)));

    }

    public static <T> List<T> getList(Class<T> classType, ResultSet rs) throws Throwable {
        List<T> Entities = new ArrayList<T>();

        //List<String> ls = MFReflect.getPropertyList(classType);

        List<String> names = getFieldNames(rs);

        //rs.beforeFirst();
        while (rs.next()) {
            T Entity = classType.newInstance();
            MFDataTransfer.<T>setEntity(Entity, rs, names);
            Entities.add(Entity);
        }
        return Entities;

    }

    public static List<String> getFieldNames(ResultSet rs) throws SQLException {
        ResultSetMetaData metaData = rs.getMetaData();
        int count = metaData.getColumnCount();

        List<String> names = new ArrayList<String>();
        for (int i = 1; i <= count; i++) {
            names.add(metaData.getColumnName(i).toUpperCase());
        }
        return names;
    }

    public static <T> void setEntity(T Entity, ResultSet rs, List<String> names) throws Throwable {

        for (String name : names) {
            Object value = rs.getObject(name);

            String relName = MFReflect.getRealPropertyName(Entity, name);
            if (MFString.notNullOrEmpty(relName)) {
                MFReflect.setDbProperty(Entity, relName, value);
            }
        }

    }

    public static MFDataClassSQLAttInfo getClassSQLInfo(Class<?> classType) {
        Annotation[] annos = classType.getAnnotations();
        MFDataClassSQLAttInfo info = new MFDataClassSQLAttInfo();
        info.setTableName(classType.getSimpleName());
        if (GlobalConfig.AUTOCASE) {
            info.setTableName(CaseUtils.classToTable(info.getTableName()));
        }
        for (Annotation anno : annos) {
            if (anno instanceof MFTable) {
                MFTable att = (MFTable) anno;

                if (MFString.notNullOrEmpty(att.tableName())) {
                    info.setTableName(att.tableName());
                }
                if (MFString.notNullOrEmpty(att.sql())) {
                    info.setSQL(att.sql());
                }
                if (MFString.notNullOrEmpty(att.orderBy())) {
                    info.setOrderBy(att.tableName());
                }
                if (MFString.notNullOrEmpty(att.where())) {
                    info.setWhere(att.where());
                }
                break;
            }

            if (anno instanceof MFTableView) {
                MFTableView att = (MFTableView) anno;
                if (MFString.notNullOrEmpty(att.tableName())) {
                    info.setTableName(att.tableName());
                }
                if (MFString.notNullOrEmpty(att.viewName())) {
                    info.setViewName(att.viewName());
                }
                if (MFString.notNullOrEmpty(att.sql())) {
                    info.setSQL(att.sql());
                }
                if (MFString.notNullOrEmpty(att.orderBy())) {
                    info.setOrderBy(att.tableName());
                }
                if (MFString.notNullOrEmpty(att.where())) {
                    info.setWhere(att.where());
                }
                if (MFString.notNullOrEmpty(att.where())) {
                    info.setWhere(att.where());
                }
                break;
            }
        }
        return info;

    }

    //DBField PropField
    public static Map<String, String> getPrimaryKeyFieldList(Class<?> classType) {
        Field[] fields = classType.getDeclaredFields();
        Map<String, String> ls = new Hashtable<String, String>();
        for (Field field : fields) {
            MFField att = field.getAnnotation(MFField.class);
            if (att != null) {
                String fieldName = att.fieldName();
                if (MFString.isNullOrEmpty(fieldName)) {
                    fieldName = field.getName();
                }
                if (att.primaryKey()) {
                    ls.put(fieldName, field.getName());
                }
            }

        }
        return ls;

    }


    public static <T> Map<String, String> getFieldPropList(T Entity) {

        return MFDataTransfer.<T>getPropList(Entity, MFField.class);
    }

    //DBField PropField
    public static <T> Map<String, String> getPropList(T Entity, Class<?> classType) {
        Map<String, String> keyList = new Hashtable<String, String>();
        Field[] fields = Entity.getClass().getDeclaredFields();
        String fieldName;
        String propName;
        for (Field field : fields) {
            if (classType != null) {
                if (field.isAnnotationPresent(MFField.class)) {
                    MFField att = field.getAnnotation(MFField.class);
                    fieldName = field.getName();
                    propName = field.getName();
                    if (MFString.notNullOrEmpty(att.fieldName())) {
                        fieldName = att.fieldName();
                    }
                    keyList.put(fieldName, propName);
                }

            } else {
                fieldName = field.getName();
                if (GlobalConfig.AUTOCASE) {
                    fieldName = CaseUtils.propToField(fieldName);
                }
                keyList.put(fieldName, field.getName());
            }

        }
        return keyList;

    }
}
